package com.synergy.stockflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.synergy.stockflow.constant.ResultCode;
import com.synergy.stockflow.entity.SysPermission;
import com.synergy.stockflow.entity.dto.SysPermDTO;
import com.synergy.stockflow.entity.vo.QuerySysPermissionVO;
import com.synergy.stockflow.exception.BusinessException;
import com.synergy.stockflow.mapper.SysPermissionMapper;
import com.synergy.stockflow.model.UserDetailsImpl;
import com.synergy.stockflow.service.SysPermissionService;
import com.synergy.stockflow.service.SysUserService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
@Transactional
@Log4j2
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements SysPermissionService {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private UserDetails userDetails;


    @Override
    public List<SysPermission> queryTree() {
        // For now, we assume that the base parent ID for the root of the permission tree is 0
        Long baseParentId = 0L;
        UserDetailsImpl principal = (UserDetailsImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Set<String> authCodes = new HashSet<>(principal.getAuthCodes());
        List<SysPermission> permissions = baseMapper.selectTree(baseParentId, authCodes);
        permissions = permissions.stream().peek(permission -> permission.setChildren(filterTree(permission.getChildren(), authCodes))).collect(Collectors.toList());
        return permissions;
    }

    private List<SysPermission> filterTree(List<SysPermission> permissions, Set<String> codes) {
        if (permissions == null || permissions.isEmpty()) {
            return Collections.emptyList();
        }

        return permissions.stream()
                .filter(perm -> perm != null && codes.contains(perm.getPerms())) // 只保留有权限的节点
                .map(perm -> {
                    // 递归处理子节点
                    List<SysPermission> filteredChildren = filterTree(perm.getChildren(), codes);
                    perm.setChildren(filteredChildren);
                    return perm;
                })
                .collect(Collectors.toList());
    }

    public List<SysPermission> list(@RequestBody QuerySysPermissionVO permission) {
        List<SysPermission> permissions = baseMapper.selectByQueryParams(permission.getName(), permission.getStatus(), permission.getType());
        return buildTree(permissions);
    }

    @Override
    public List<SysPermission> listMenu(QuerySysPermissionVO vo) {
        vo.setStatus(1);
        return baseMapper.selectByQueryParams(vo.getName(), vo.getStatus(), vo.getType());
    }

    @Override
    public Boolean insertPerm(SysPermDTO dto) {
        Date date = new Date();
        Long parentId = dto.getParentId();
        if (parentId != 0) {
            SysPermission parent = this.getById(parentId);
            String parentName = parent.getName();
            dto.setParentName(parentName);
        }
        SysPermission permission = new SysPermission();
        BeanUtils.copyProperties(dto, permission);
        permission.setCreateBy(sysUserService.currentUser().getId());
        permission.setCreateTime(date);
        // 唯一性判断 name, path, perms
        LambdaQueryWrapper<SysPermission> uniqueQueryWrapper = new LambdaQueryWrapper<>();
        uniqueQueryWrapper.eq(SysPermission::getName, permission.getName());
        List<SysPermission> uniqueNameList = this.list(uniqueQueryWrapper);
        if (uniqueNameList != null && !uniqueNameList.isEmpty()) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "权限名称已存在");
        }
        uniqueQueryWrapper = new LambdaQueryWrapper<>();
        uniqueQueryWrapper.eq(SysPermission::getPath, permission.getPath());
        List<SysPermission> uniquePathList = this.list(uniqueQueryWrapper);
        if (uniquePathList != null && !uniquePathList.isEmpty()) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "权限路径已存在");
        }
        uniqueQueryWrapper = new LambdaQueryWrapper<>();
        uniqueQueryWrapper.eq(SysPermission::getPerms, permission.getPerms());
        List<SysPermission> uniquePermsList = this.list(uniqueQueryWrapper);
        if (uniquePermsList != null && !uniquePermsList.isEmpty()) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "权限标识已存在");
        }
        return this.save(permission);
    }

    @Override
    public Boolean updatePerm(SysPermDTO dto) {
        Date date = new Date();
        Long parentId = dto.getParentId();
        if (parentId != 0) {
            SysPermission parent = this.getById(parentId);
            String parentName = parent.getName();
            dto.setParentName(parentName);
        }
        SysPermission permission = new SysPermission();
        BeanUtils.copyProperties(dto, permission);
        permission.setUpdateBy(sysUserService.currentUser().getId());
        permission.setUpdateTime(date);

        LambdaQueryWrapper<SysPermission> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysPermission::getName, permission.getName());
        SysPermission one = this.getOne(queryWrapper);
        // 唯一性判断 name, path, perms
        LambdaQueryWrapper<SysPermission> uniqueQueryWrapper = new LambdaQueryWrapper<>();
        uniqueQueryWrapper.eq(SysPermission::getPath, permission.getPath());
        uniqueQueryWrapper.ne(SysPermission::getId, permission.getId());
        List<SysPermission> uniquePathList = this.list(uniqueQueryWrapper);
        if (uniquePathList != null && !uniquePathList.isEmpty()) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "权限路径已存在");
        }
        uniqueQueryWrapper = new LambdaQueryWrapper<>();
        uniqueQueryWrapper.eq(SysPermission::getPerms, permission.getPerms());
        uniqueQueryWrapper.ne(SysPermission::getId, permission.getId());
        List<SysPermission> uniquePermsList = this.list(uniqueQueryWrapper);
        if (uniquePermsList != null && !uniquePermsList.isEmpty()) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "权限标识已存在");
        }

        permission.setId(one.getId());
        permission.setCreateBy(one.getCreateBy());
        permission.setCreateTime(one.getCreateTime());
        return this.updateById(permission);
    }

    private List<SysPermission> buildTree(List<SysPermission> permissions) {
        Map<Long, SysPermission> map = new HashMap<>();

        List<SysPermission> result = new ArrayList<>();

        // 先把所有节点放入 map
        for (SysPermission node : permissions) {
            map.put(node.getId(), node);
        }

        // 遍历，把子节点挂到父节点上
        for (SysPermission node : permissions) {
            Long parentId = node.getParentId();
            if (parentId == null || parentId == 0 || !map.containsKey(parentId)) {
                result.add(node); // 根节点
            } else {
                SysPermission parent = map.get(parentId);
                List<SysPermission> parentChildren = parent.getChildren();
                if (parentChildren == null || parentChildren.isEmpty()) {
                    parentChildren = new ArrayList<>();
                    parentChildren.add(node);
                    parent.setChildren(parentChildren);
                    continue;
                }
                parentChildren.add(node);
                parent.setChildren(parentChildren);
            }
        }
        return result;
    }
}
